package de.schule.barnimgymnasium.javafx;

import java.net.InetAddress;

import javafx.application.Application;
import javafx.concurrent.WorkerStateEvent;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.TextField;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;
import javafx.scene.text.Text;
import javafx.stage.Stage;
import de.schule.barnimgymnasium.javafx.broadcaster.Network;
import de.schule.barnimgymnasium.javafx.broadcaster.Network.IncomingObject;

/**
 * @author uwe.hermann Stand des Programmes zu Beginn des 8. Tages
 * 
 */
public class StartDay09 extends Application {

	/*
	 * (non-Javadoc)
	 * 
	 * @see javafx.application.Application#start(javafx.stage.Stage)
	 */
	@Override
	public void start(Stage primaryStage) throws Exception {
		// Objekt zum Senden und Empfangen von serialisierbaren Objekten über
		// das Broadcast-Netzwerk
		final Network network = new Network();
		// Grafisches Element zum Anzeigen der eingegangenen und gesendeten
		// Nachrichten
		final VBox nachrichtenanzeigebereich = new VBox();
		// Grafisches Element zum Schreiben einer neuen Nachricht
		final TextField nachrichteneingabezeile = new TextField();
		// Was soll passieren, wenn in der Eingabezeile "ENTER" gedrückt wird
		nachrichteneingabezeile.setOnAction(new EventHandler<ActionEvent>() {

			/**
			 * Diese Methode wird aufgerufen, wenn in der Eingabezeile "ENTER"
			 * gedrückt wurde. Sie holt den Nachrichtentext aus der
			 * Eingabezeile, sorgt für die Darstellung der Nachricht im eigenen
			 * Programm, versendet die Nachricht und bereitet die Eingabezeile
			 * auf das Schreiben einer neuen Nachricht vor - löscht also die
			 * alte Nachricht aus der Eingabezeile.
			 * 
			 * @param arg0
			 */
			@Override
			public void handle(ActionEvent arg0) {
				String nachricht = nachrichteneingabezeile.getText();
				nachrichteneingabezeile.clear();
				// Wir wollen die selbst geschriebenen Nachrichten auch selbst sehen.
				nachrichtenanzeigebereich.getChildren().add(createNachrichtenDisplay(nachricht, null));
				network.broadcastObject(nachricht);
			}
		});
		// Was soll passieren, wenn der Rechner vom Netzwerk EIN Datenpaket
		// empfangen hat? Es muss sich dabei nicht zwangsweise um eine
		// anzeigbare Nachricht handeln!
		network.setOnSucceeded(new EventHandler<WorkerStateEvent>() {

			/**
			 * Diese Methode wird aufgerufen, wenn von einem Netzwerkadapter
			 * irgendwelche Daten für dieses Programm empfangen wurden. Derzeit
			 * prüft sie, ob es sich bei dem empfangenen Objekt um einen String
			 * handelt und stellt diesen dann im Nachrichtenanzeigebereich dar.
			 * Aber was passiert, wenn wir keinen String sondern ein Bild
			 * empfangen?
			 * 
			 * @param ev
			 */
			@Override
			public void handle(final WorkerStateEvent ev) {
				IncomingObject incoming = network.getValue();
				Object obj = incoming.getObject();
				if (obj instanceof String) {
					// Beim empfangenen Objekt handelt es sich um einen ganz einfachen String - also eine Text-Nachricht
					String nachricht = (String) obj;
					if (!network.getLocalAddresses().contains(incoming.getAddress()) ) {
						nachrichtenanzeigebereich.getChildren().add(createNachrichtenDisplay(nachricht, incoming.getAddress()));
					}
				}
				// Nach der Verarbeitung dieses Datenpaketes soll der Rechner
				// auf ein weiteres Paket warten.
				network.restart();
			}
		});
		// Der Rechner soll auf Daten vom Netzwerk warten.
		network.start();
		// Anordnung der grafischen Elemente in der Scene
		VBox pane = new VBox();
		VBox.setVgrow(nachrichtenanzeigebereich, Priority.ALWAYS);
		ScrollPane scrollPane =new ScrollPane();
		VBox.setVgrow(scrollPane, Priority.ALWAYS);
		scrollPane.setContent(nachrichtenanzeigebereich);
		scrollPane.setFitToWidth(true);
		pane.getChildren().add(scrollPane);
		pane.getChildren().add(nachrichteneingabezeile);
		primaryStage.setScene(new Scene(pane, 600, 500));
		primaryStage.setTitle("Scäib");
		primaryStage.show();
	}
	
	/**
	 * Diese Methode erzeugt ein anzeigbares Element aus dem Text einer empfangenen Nachricht und der IP-Adresse des Absenders. 
	 * @param nachricht Der anzuzeigende Nachrichtentext
	 * @param absender Die IP-Adresse des Absenders
	 * @return Ein anzeigbares grafisches Element
	 */
	protected Node createNachrichtenDisplay(String nachricht, InetAddress absender) {
		// Angaben über den Absender der Nachricht
		Text ip = new Text();
		ip.setText("" + (absender == null ? "Ich: " : absender.getHostAddress()));
		// Der Text der Nachricht
		Label lbl = new Label();
		lbl.setWrapText(true);
		lbl.setText(nachricht);
		// Nebeneinanderstellen von Absenderinformationen und Nachricht
		HBox hbox = new HBox();
		hbox.getChildren().addAll(ip,lbl);
		// Die Anzeige des Nachrichteninhaltes soll sich immer so breit machen wie möglich.
		HBox.setHgrow(lbl, Priority.ALWAYS);
		// Das erzeugte grafische Element (die Nebeneinanderstellung von Absenderinfos und Nachichteninhalt) wird zurück gegeben
		return hbox;
	}
	
	/**
	 * Start des Programmes
	 * 
	 * @param args
	 */
	public static void main(final String[] args) {
		// Start der JavaFX-Anzeige
		Application.launch(args);
	}
}
